﻿Namespace Abstraction
    Public Class FileLoader
        Private _allowExternalFiles As Boolean
        Public Property AllowExternalFiles As Boolean
            Get
                Return _allowExternalFiles
            End Get
            Set(value As Boolean)
                _allowExternalFiles = value

                If _mountedPackages.Count > 0 Then
                    For Each item In _mountedPackages
                        item.Value.AllowExternalFiles = value
                    Next
                End If
            End Set
        End Property
        Public Property AllowExternalFiles(ByVal key As Integer) As Boolean
            Get
                If _mountedPackages.ContainsKey(key) Then Return _mountedPackages(key).AllowExternalFiles

                Throw New IO.FileNotFoundException()
            End Get
            Set(value As Boolean)
                If _mountedPackages.ContainsKey(key) Then _mountedPackages(key).AllowExternalFiles = value
            End Set
        End Property
        Private _active As Boolean
        Public Property Active As Boolean
            Get
                Return _active
            End Get
            Set(value As Boolean)
                If _mountedPackages.Count > 0 Then
                    For Each item In _mountedPackages
                        item.Value.Active = value
                    Next
                End If

                _active = value
            End Set
        End Property
        Public Property Active(ByVal key As Integer) As Boolean
            Get
                If _mountedPackages.ContainsKey(key) Then Return _mountedPackages(key).Active

                Throw New IO.FileNotFoundException()
            End Get
            Set(value As Boolean)
                If _mountedPackages.ContainsKey(key) Then _mountedPackages(key).Active = value
            End Set
        End Property
        Public ReadOnly Property PackageCount As Integer
            Get
                Return _mountedPackages.Count
            End Get
        End Property

        Public Event DebugLogEvent(ByVal text As String)
        Private Sub AddLog(Optional ByVal text As String = "")
            RaiseEvent DebugLogEvent(text)
        End Sub
        Private Sub __bridge_DebugLogEvent(ByVal text As String)
            RaiseEvent DebugLogEvent(text)
        End Sub

        Private _mountedPackages As New System.Collections.Generic.Dictionary(Of String, FileSystemAbstraction)(32)

        Public Function FileExists(ByVal filename As String) As Boolean
            If _mountedPackages.Count < 1 Then Return False

            For Each item In _mountedPackages
                If item.Value.Active Then
                    If item.Value.FileExists(filename) Then Return True
                End If
            Next

            Return False
        End Function
        Public Function DirectoryExists(ByVal directory As String) As Boolean
            If _mountedPackages.Count < 1 Then Return False

            For Each item In _mountedPackages
                If item.Value.Active Then
                    If item.Value.DirectoryExists(directory) Then Return True
                End If
            Next

            Return False
        End Function
        Public Function FileLength(ByVal filename As String) As Long
            If _mountedPackages.Count < 1 Then Return -1

            For Each item In _mountedPackages
                If item.Value.Active Then
                    Dim size As Long = item.Value.FileLength(filename)
                    If size >= 0 Then Return size
                End If
            Next

            Return -1
        End Function
        Public Function GetFiles(ByVal path As String, Optional ByVal filter As String = "*") As String()
            If _mountedPackages.Count < 1 Then Return Nothing

            Dim output As New Dictionary(Of String, Byte)(64)

            For Each item In _mountedPackages
                If item.Value.Active Then
                    Dim files() As String = item.Value.GetFiles(path, filter)
                    If files IsNot Nothing Then
                        Dim i As Integer
                        For i = 0 To files.Length - 1
                            files(i) = LCase(files(i))
                            If Not output.ContainsKey(files(i)) Then output.Add(files(i), 0)
                        Next
                    End If
                End If
            Next

            Dim plainOutput As New ArrayList(output.Count + 1)
            For Each item In output
                plainOutput.Add(item.Key)
            Next

            Return plainOutput.ToArray()
        End Function
        Public Function GetDirectories(ByVal path As String, Optional ByVal filter As String = "*") As String()
            If _mountedPackages.Count < 1 Then Return Nothing

            Dim output As New Dictionary(Of String, Byte)(64)

            For Each item In _mountedPackages
                If item.Value.Active Then
                    Dim dirs() As String = item.Value.GetDirectories(path, filter)
                    If dirs IsNot Nothing Then
                        Dim i As Integer
                        For i = 0 To dirs.Length - 1
                            dirs(i) = LCase(dirs(i))
                            If Not output.ContainsKey(dirs(i)) Then output.Add(dirs(i), 0)
                        Next
                    End If
                End If
            Next

            Dim plainOutput As New ArrayList(output.Count + 1)
            For Each item In output
                plainOutput.Add(item.Key)
            Next

            If plainOutput.Count < 1 Then Return Nothing

            Dim outBuffer(plainOutput.Count - 1) As String
            Dim x As Integer
            For x = 0 To plainOutput.Count - 1
                outBuffer(x) = plainOutput(x)
            Next

            Return outBuffer
        End Function
        Public Function GetFileStream(ByVal filename As String) As System.IO.Stream
            If _mountedPackages.Count < 1 Then Return Nothing

            For Each package In _mountedPackages
                If package.Value.FileExists(filename) Then
                    Return package.Value.GetFileStream(filename)
                End If
            Next

            Return Nothing
        End Function

        Public Function MountPackage(ByVal name As String, ByVal filename As String, ByVal unpackedPath As String, Optional ByVal pallowExternalFiles As Boolean = False, Optional ByVal pactive As Boolean = True) As Engine.PackageMountReturnCode
            AddLog("ArpsFileLoader::Inserting package <" & name & "> into application.")

            Dim package As New FileSystemAbstraction(filename, unpackedPath, False)
            AddHandler package.DebugLineGenerated, AddressOf __bridge_DebugLogEvent

            package.AllowExternalFiles = pallowExternalFiles

            If pactive Then
                package.Active = True

                If Not package.LastReturnCode = Engine.PackageMountReturnCode.MountSuccess Then
                    AddLog("ArpsFileLoader::ERROR!: Cant insert package <" & name & ">. Code <" & package.LastReturnCode.ToString & ">")
                    RemoveHandler package.DebugLineGenerated, AddressOf __bridge_DebugLogEvent
                    Return package.LastReturnCode
                End If
            End If

            _mountedPackages.Add(name, package)

            Return Engine.PackageMountReturnCode.MountSuccess
        End Function
        Public Sub UnmountPackage(ByVal name As String)
            If _mountedPackages.ContainsKey(name) Then
                AddLog("ArpsFileLoader::Package <" & name & "> removed from application.")
                Dim item As FileSystemAbstraction = _mountedPackages(name)
                item.Active = False
                RemoveHandler item.DebugLineGenerated, AddressOf __bridge_DebugLogEvent

                _mountedPackages.Remove(name)
            Else
                AddLog("ArpsFileLoader::WARNING!: Tried to unmount unknown package <" & name & ">")
            End If
        End Sub
        Public Sub UnmountAll()
            If _mountedPackages.Count < 1 Then Exit Sub

            Dim q As New Queue(_mountedPackages.Count + 1)
            For Each item In _mountedPackages
                q.Enqueue(item.Key)
            Next

            Do Until q.Count < 1
                UnmountPackage(q.Dequeue)
            Loop

            AddLog("ArpsFileLoader::All packages removed from application.")
        End Sub
    End Class
End Namespace

